﻿namespace LivePatterns
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Reflection;

	internal static class TypeExtensions
	{
		private const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		public static IEnumerable<PropertyInfo> GetAllVisibleProperties(this Type type)
		{
			HashSet<PropertyInfo> result = new HashSet<PropertyInfo>();
			IncludeInheritedProperties(type, result);
			return result;
		}

		private static void IncludeInheritedProperties(Type type, ICollection<PropertyInfo> properties)
		{
			foreach (PropertyInfo pi in type.GetProperties(bindingFlags))
				properties.Add(pi);

			foreach (Type parentInterface in type.GetInterfaces())
				IncludeInheritedProperties(parentInterface, properties);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		public static IEnumerable<MethodInfo> GetAllVisibleMethods(this Type type)
		{
			HashSet<MethodInfo> result = new HashSet<MethodInfo>();
			IncludeInheritedMethods(type, result);
			return result;
		}

		private static void IncludeInheritedMethods(Type type, ICollection<MethodInfo> methods)
		{
			foreach (MethodInfo pi in type.GetMethods(bindingFlags).Where(m => !m.IsSpecialName))
				methods.Add(pi);

			foreach (Type parentInterface in type.GetInterfaces())
				IncludeInheritedMethods(parentInterface, methods);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="type"></param>
		/// <returns></returns>
		public static IEnumerable<EventInfo> GetAllVisibleEvents(this Type type)
		{
			HashSet<EventInfo> result = new HashSet<EventInfo>();
			IncludeInheritedEvents(type, result);
			return result;
		}

		private static void IncludeInheritedEvents(Type type, ICollection<EventInfo> methods)
		{
			foreach (EventInfo pi in type.GetEvents(bindingFlags))
				methods.Add(pi);

			foreach (Type parentInterface in type.GetInterfaces())
				IncludeInheritedEvents(parentInterface, methods);
		}
	}
}
